package com.example.zhihu.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.thread.ExecutorBuilder;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.zhihu.entity.HotInfo;
import com.example.zhihu.mapper.HotInfoMapper;
import com.example.zhihu.service.IHotInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.zhihu.util.HttpUtils;
import com.example.zhihu.util.MapUtil;
import com.example.zhihu.vo.HotInfoVo;
import com.example.zhihu.vo.HotInfoVo2;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author author
 * @since 2022-04-17
 */
@Service
public class HotInfoServiceImpl extends ServiceImpl<HotInfoMapper, HotInfo> implements
    IHotInfoService {

  @Resource
  HotInfoMapper hotInfoMapper;

  @Override
  public List<HotInfo> first(Integer count, String currentDate) {
    // 创造时间区间
    String startTime = currentDate + " 00:00:00";
    String endTime = currentDate + " 23:59:59";
    // 先按照时间排序获取前50条
    List<HotInfo>  hotInfoList = hotInfoMapper.first(startTime, endTime);

    // 再取出前10条
    return hotInfoList.stream()
        .sorted(((o1, o2) -> o2.getHotIndex().compareTo(o1.getHotIndex()))).limit(10)
        .collect(Collectors.toList());
  }

  @Override
  public void addKeyword(List<HotInfo> hotInfoList) {
    // 这里尝试创建多线程
    ExecutorService executor = ExecutorBuilder.create()
        .setCorePoolSize(5)
        .setMaxPoolSize(50)
        .useSynchronousQueue()
        .build();

    List<CompletableFuture<Boolean>> futures = new ArrayList<>();
    Map<String, List<String>> map = new HashMap<>();
    Map<String, Integer> visitMap = new HashMap<>();
    // 遍历HotInfoList，使用多线程抓取关键词
    for (HotInfo hotInfo : hotInfoList) {
      CompletableFuture<Boolean> future = CompletableFuture.supplyAsync(() -> {
        String html = HttpUtils.doGetHtml(hotInfo.getUrl());
        Document document = Jsoup.parse(html);
        // 取出关键词
        Elements elements = document.body().select(".QuestionTopic");
        List<String> keywordList = new ArrayList<>();

        for (Element element : elements) {
          keywordList.add(element.text());
        }
        map.put(hotInfo.getInfoId(), keywordList);
        // 取出浏览量
        Elements elements1 = document.body().select(".NumberBoard-itemValue");
        Element element = elements1.get(1);
        String title = element.attr("title");
        visitMap.put(hotInfo.getInfoId(), Integer.parseInt(title));
        return true;
      }, executor);
      futures.add(future);
    }
    // 全部执行完了之后，聚合结果
    for (CompletableFuture<Boolean> future : futures) {
      try {
        // 最多等5秒钟
        future.get(5, TimeUnit.SECONDS);
      } catch (InterruptedException | ExecutionException | TimeoutException e) {
        e.printStackTrace();
      }
    }

    // 按照map更新hostInfoList
    for (HotInfo hotInfo : hotInfoList) {
      List<String> keywordList = map.get(hotInfo.getInfoId());
      Integer visitCount = visitMap.get(hotInfo.getInfoId());
      String s = StrUtil.join(",", keywordList);
      hotInfo.setKeyword(s);
      if (CollectionUtil.isNotEmpty(keywordList)) {
        hotInfo.setFirstword(keywordList.get(0));
        hotInfo.setVisitCount(visitCount);
      }
    }
  }


  public List<HotInfoVo> addUnusual(List<HotInfo> hotInfoList1) {
    List<HotInfoVo> hotInfoVoList = new ArrayList<>();
    // 获取每个话题在数据库中的当天的所有数据
    for (int i=0; i<hotInfoList1.size(); i++) {
      HotInfo hotInfo = hotInfoList1.get(i);
      HotInfoVo hotInfoVo = new HotInfoVo();
      BeanUtils.copyProperties(hotInfo, hotInfoVo);
      hotInfoVo.setCurrentRank(i + 1);

      // 计算增长值
      List<HotInfo> hotInfos = listByInfoId(hotInfo.getInfoId(), hotInfo.getInsertTime());
      Integer addedAnswerCount = hotInfos.get(0).getAnswerCount() - hotInfos.get(hotInfos.size() - 1).getAnswerCount();
      hotInfoVo.setAddedAnswerCount(addedAnswerCount);
      hotInfoVoList.add(hotInfoVo);
    }

    hotInfoVoList = hotInfoVoList.stream().sorted(new Comparator<HotInfoVo>() {
      @Override
      public int compare(HotInfoVo o1, HotInfoVo o2) {
        if(o2.getAddedAnswerCount() > o1.getAddedAnswerCount()) {
          return 1;
        } else if(o2.getAddedAnswerCount() < o1.getAddedAnswerCount()) {
          return -1;
        }
        return 0;
      }
    }).collect(Collectors.toList());
    for(int i=0; i<hotInfoVoList.size(); i++) {
      HotInfoVo hotInfoVo = hotInfoVoList.get(i);
      hotInfoVo.setRealRank(i + 1);
      if(hotInfoVo.getRealRank() - hotInfoVo.getCurrentRank() >= 2) {
        hotInfoVo.setIsUnusual(true);
      }
    }
    return hotInfoVoList;
  }

  /**
   * 根据id获取当前的所有数据
   * @param infoId
   * @return
   */
  public List<HotInfo> listByInfoId(String infoId, LocalDateTime dateTime) {
    QueryWrapper<HotInfo> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("info_id", infoId);
    queryWrapper.between("insert_time", LocalDateTimeUtil.beginOfDay(dateTime),
        LocalDateTimeUtil.endOfDay(dateTime));
    queryWrapper.orderByDesc("insert_time");
    return this.list(queryWrapper);
  }

  public List<HotInfoVo2> convert2Vo2(List<HotInfo> hotInfoList) {
    List<HotInfoVo2> hotInfoVo2List = hotInfoList.stream().map(hotInfo -> {
      HotInfoVo2 hotInfoVo2 = new HotInfoVo2();
      BeanUtils.copyProperties(hotInfo, hotInfoVo2);
      LocalDateTime insertTime = hotInfoVo2.getInsertTime();
      int hour = insertTime.getHour();
      hotInfoVo2.setCurrentHour(hour);
      return hotInfoVo2;
    }).sorted((o1, o2) -> {
      if(o1.getInsertTime().isAfter(o2.getInsertTime())) {
        return 1;
      } else if (o1.getInsertTime().isBefore(o2.getInsertTime())) {
        return -1;
      } else {
        return 0;
      }
    }).collect(Collectors.toList());

    // 去掉小时重复的数据
    Map<Integer, HotInfoVo2> map = new HashMap<>();
    for (HotInfoVo2 hotInfoVo2 : hotInfoVo2List) {
      map.put(hotInfoVo2.getCurrentHour(), hotInfoVo2);
    }

    List<HotInfoVo2> hotInfoVo2s = new ArrayList<>();
    map.forEach((integer, hotInfoVo2) -> hotInfoVo2s.add(hotInfoVo2));
    return hotInfoVo2s.stream().sorted(Comparator.comparing(HotInfoVo2::getCurrentHour)).collect(Collectors.toList());
  }
}
